﻿#if NET8_0_OR_GREATER
using System.Diagnostics.CodeAnalysis;
#endif
using System;
using System.Collections.Generic;
using System.Linq;
using DimensionsHelper.Common.Contracts.DataCollector.Options;
using DimensionsHelper.Common.Utils;

namespace DimensionsHelper.Services.DataCollector.Options;

public class OptionHelper(Validator validator)
{
    private readonly Dictionary<Export, FilterCacheCollection> _filterCache = new();
    private readonly Dictionary<Gap, GapIdentifierCacheCollection> _gapIdentifierCaches = new();
    private readonly Dictionary<string, Dictionary<string, RegexManager>> _groupMap = new();
    private readonly List<GroupType> _notNullTypes = [];
    private readonly Dictionary<Export, IList<string>> _orderCache = new();
    private readonly Dictionary<string, RegexManager> _testingValueMap = new();
    private readonly Dictionary<string, ReplacerCache> _typeReplacerCache = new();

    public OptionHelper(CollectorOptions options, Validator validator) : this(validator)
    {
        SetOptions(options);
    }

    public CollectorOptions Options { get; private set; } = new();

    public Validator Validator { get; } = validator;


    public bool IsInitialized { get; private set; }

    /// <summary>
    ///     配置中不允许空白的类型列表。
    /// </summary>
    public IReadOnlyList<GroupType> NotNullTypes => _notNullTypes;

    public GroupType? EntryType { get; private set; }

    public GroupType ColumnKeyType => Options.Types.Settings[Options.Types.ColumnKey];


    private static void UpdateValueRegex(RegexManager regexManager, Testing testing)
    {
        if (testing.IsPattern)
        {
            regexManager.AppendExpression(testing.Values, testing.Name);
        }
        else
        {
            regexManager.Append(testing.Values, testing.Name);
        }
    }


    private void ClearStorage()
    {
        _notNullTypes.Clear();
        _testingValueMap.Clear();
        _groupMap.Clear();
        _typeReplacerCache.Clear();
    }

    private void InitTypeReplacer(GroupType type)
    {
        if (!_typeReplacerCache.TryGetValue(type.Name, out var cache))
        {
            cache = new ReplacerCache(type);
            _typeReplacerCache.Add(type.Name, cache);
        }

        // 初始化替换值
        for (var i = 0; i < type.Values.Count; i++)
        {
            if (type.IsPattern)
            {
                cache.ValueRegex.AppendExpression(type.Values[i]);
            }
            else
            {
                cache.ValueRegex.Append(type.Values[i]);
            }

            string? replaceText = null;

            if (type.Replacements != null && i < type.Replacements.Count)
            {
                replaceText = type.Replacements[i];
            }

            if (replaceText == null)
            {
                cache.Replacers.Add(null);
                // 没有对应的替换值时，添加原始值
                cache.FinalValues.Add(type.Values[i]);
            }
            else
            {
                Replacer? rep;

                try
                {
                    rep = ReplacerParser.Parse(replaceText);
                }
                catch (Exception e)
                {
                    rep = null;
                    Validator.ReportService?.Error(e.Message);
                }

                cache.Replacers.Add(rep);
                string? text = null;

                if (rep != null)
                {
                    // 如果是纯文本，直接添加
                    text = rep.IsPureText
                        ? rep.Replace(null)
                        :
                        // 次优先添加保留值
                        rep.Remaining;

                    // 检查是否包含别名
                    if (!cache.HasAlias && !string.IsNullOrEmpty(rep.Alias))
                    {
                        cache.HasAlias = true;
                    }
                }

                // 否则，添加原始值
                text ??= type.Values[i];
                cache.FinalValues.Add(text);
            }
        }
    }


    private void Initialize()
    {
        ClearStorage();

        if (!Validator.Validate(Options))
        {
            IsInitialized = false;
            return;
        }

        if (!string.IsNullOrEmpty(Options.Types.Entry) &&
            Options.Types.Settings.TryGetValue(Options.Types.Entry!, out var entry))
        {
            EntryType = entry;
        }

        foreach (var item in Options.Types.Settings)
        {
            if (!item.Value.Nullable)
            {
                _notNullTypes.Add(item.Value);
            }

            InitTypeReplacer(item.Value);
        }

        foreach (var testing in Options.Testings)
        {
            // 如果 Testing 用于分组，添加到 groupMap
            if (!string.IsNullOrEmpty(testing.Value.GroupName))
            {
                if (!_groupMap.TryGetValue(testing.Value.GroupName, out var group))
                {
                    group = new Dictionary<string, RegexManager>();
                    _groupMap.Add(testing.Value.GroupName, group);
                }

                if (!group.TryGetValue(testing.Value.Name, out var cache))
                {
                    cache = new RegexManager
                    {
                        IgnoreCase = testing.Value.IgnoreCase,
                        Exactly = testing.Value.Exactly
                    };

                    group.Add(testing.Value.Name, cache);
                }

                UpdateValueRegex(cache, testing.Value);
            }
            else
            {
                var regex = new RegexManager()
                {
                    IgnoreCase = testing.Value.IgnoreCase,
                    Exactly = testing.Value.Exactly
                };

                UpdateValueRegex(regex, testing.Value);
                _testingValueMap.SetValue(testing.Key, regex);
            }
        }

        InitGaps();
        IsInitialized = true;
    }

    public void SetOptions(CollectorOptions options)
    {
        Options = options;
        Initialize();
    }


    private GapIdentifierCacheCollection GetCache(Gap gap)
    {
        if (_gapIdentifierCaches.TryGetValue(gap, out var cache))
        {
            return cache;
        }

        cache = new GapIdentifierCacheCollection(gap);
        _gapIdentifierCaches.Add(gap, cache);

        return cache;
    }


    private void InitGaps()
    {
        foreach (var gap in Options.Gaps.Values)
        {
            // 优先使用 Gap.Expression
            if (!string.IsNullOrEmpty(gap.Expression))
            {
                try
                {
                    GetCache(gap).AddSimpleExpression(gap.Expression);
                }
                catch (Exception e)
                {
                    Validator.ReportService?.Error(e.Message);
                }
            }
            // 只初始化带有 Identifier 内容的配置。
            else if (gap.Identifiers.Count > 0)
            {
                foreach (var id in gap.Identifiers)
                {
                    // 只初始化 GapIdentifier.Type 不是空的配置
                    if (!string.IsNullOrEmpty(id.Type))
                    {
                        GetCache(gap).Add(id.Type, id.Value);
                    }
                }
            }
        }
    }


    /// <summary>
    ///     获取指定类型名的最终值列表。
    /// </summary>
    /// <param name="typeName">类型名</param>
    public List<string> GetFinalValues(string typeName)
    {
        return _typeReplacerCache.TryGetValue(typeName, out var cache)
            ? cache.FinalValues.ToList()
            : [];
    }


    public bool TryGetTypeFromValue(string value, 
#if NET8_0_OR_GREATER
            [MaybeNullWhen(false)]
#endif
        out GroupType groupType)
    {
        groupType = null!;

        foreach (var cache in _typeReplacerCache.Values.Where(cache => cache.ValueRegex.IsMatch(value)))
        {
            groupType = cache.TypeObj;
            return true;
        }

        return false;
    }

    public bool TryGetType(string typeName, 
#if NET8_0_OR_GREATER
            [MaybeNullWhen(false)]
#endif
        out GroupType typeObj)
    {
        return Options.Types.Settings.TryGetValue(typeName, out typeObj);
    }


    /// <summary>
    ///     如果给定类型名值定义包含别名，返回true。
    /// </summary>
    public bool IsTypeContainsAlias(string typeName)
    {
        return _typeReplacerCache.TryGetValue(typeName, out var cache) && cache.HasAlias;
    }


    public bool TryTest(string testingName, string value,
#if NET8_0_OR_GREATER
            [MaybeNullWhen(false)]
#endif
        out string markText)
    {
        markText = null!;

        if (string.IsNullOrEmpty(testingName) || !Options.Testings.TryGetValue(testingName, out var testing))
        {
            return false;
        }

        if (_testingValueMap.TryGetValue(testingName, out var regexp) && regexp.IsMatch(value))
        {
            markText = testing.Fit;
        }
        else
        {
            markText = testing.Unfit;
        }

        return true;
    }

    /// <summary>
    ///     获取已定义的分组成员名。
    /// </summary>
    public bool TryGetGroupMemberNames(string? groupName, out IList<string> groupMemberNames)
    {
        groupMemberNames = null!;

        if (groupName == null || !_groupMap.TryGetValue(groupName, out var groupItem))
        {
            return false;
        }

        groupMemberNames = groupItem.Keys.ToList();
        return true;
    }

    /// <summary>
    ///     尝试查找给定值的分组名，如果成功查找到，返回true，memberNames中是所有符合的分组名；如果未查找到，返回false，memberNames列表为空。
    /// </summary>
#if NET8_0_OR_GREATER
        public bool TryFindGrouping(string? groupName, string value,
            [NotNullWhen(true)] out IEnumerable<string>? memberNames)
#else
    public bool TryFindGrouping(string? groupName, string value, out IEnumerable<string> memberNames)
#endif
    {
        memberNames = null!;

        if (groupName == null || !_groupMap.TryGetValue(groupName, out var groupItem))
        {
            return false;
        }

        var names = new List<string>();

        foreach (var item in groupItem.Values)
        {
            names.AddRange(item.SearchGroups(value).Select(tuple => tuple.GroupName));
        }

        memberNames = names;
        return names.Count > 0;
    }


    public ThresholdTestResult TestThreshold(string thresholdName, double testValue)
    {
        if (string.IsNullOrEmpty(thresholdName) || double.IsNaN(testValue) ||
            !Options.Thresholds.TryGetValue(thresholdName, out var threshold))
        {
            return ThresholdTestResult.NaN;
        }

        if (!double.IsNaN(threshold.Lower))
        {
            if (threshold.IsClosed ? testValue < threshold.Lower : testValue <= threshold.Lower)
            {
                return ThresholdTestResult.Less;
            }

            if (!double.IsNaN(threshold.Upper) &&
                (threshold.IsClosed ? testValue <= threshold.Upper : testValue < threshold.Upper))
            {
                return ThresholdTestResult.Exactly;
            }

            return ThresholdTestResult.Greater;
        }

        // 此处 threshold.Lower 已经为空
        if (double.IsNaN(threshold.Upper))
        {
            return ThresholdTestResult.NaN;
        }

        if (threshold.IsClosed ? testValue > threshold.Upper : testValue >= threshold.Upper)
        {
            return ThresholdTestResult.Greater;
        }

        return ThresholdTestResult.Less;
    }


    private bool IsTypeValue(string type, string value)
    {
        return _typeReplacerCache.TryGetValue(type, out var cache) && cache.ValueRegex.IsMatch(value);
    }


    public bool IsColumnKeyTypeValue(string value)
    {
        return IsTypeValue(Options.Types.ColumnKey, value);
    }


    /// <summary>
    ///     使用原始值查找对应的别名
    /// </summary>
#if NET8_0_OR_GREATER
        public bool TryGetAliasBySourceValue(string typeName, string value, 
            [MaybeNullWhen(false)] out string alias)
#else
    public bool TryGetAliasBySourceValue(string typeName, string value, out string alias)
#endif
    {
        alias = null!;

        if (string.IsNullOrEmpty(value) ||
            !_typeReplacerCache.TryGetValue(typeName, out var cache) ||
            !cache.TryGetReplacer(value, out var replacer) ||
            string.IsNullOrEmpty(replacer.Alias))
        {
            return false;
        }

        alias = replacer.Alias!;
        return true;
    }


    /// <summary>
    ///     使用替换值查找别名
    /// </summary>
#if NET8_0_OR_GREATER
        public bool TryGetAliasByReplacement(string typeName, string value, 
            [MaybeNullWhen(false)] out string alias)
#else
    public bool TryGetAliasByReplacement(string typeName, string value, out string alias)
#endif
    {
        alias = null!;

        if (string.IsNullOrEmpty(value) ||
            !_typeReplacerCache.TryGetValue(typeName, out var cache) ||
            !cache.FinalValues.Contains(value))
        {
            return false;
        }

        var find = cache.Replacers.Find(r => r != null && r.Replace(null) == value);

        if (find == null || string.IsNullOrEmpty(find.Alias))
        {
            return false;
        }

        alias = find.Alias!;
        return true;
    }


    public string? TryGetTypeValue(string typeName, string value, Func<string, string?>? getter)
    {
        if (string.IsNullOrEmpty(value) ||
            !_typeReplacerCache.TryGetValue(typeName, out var cache))
        {
            return null;
        }

        return cache.GetText(value, getter);
    }


#if NET8_0_OR_GREATER
        public bool TryGetTypeValue(string typeName, string value, 
            [MaybeNullWhen(false)] out string typeValue)
#else
    public bool TryGetTypeValue(string typeName, string value, out string typeValue)
#endif
    {
        typeValue = null!;

        if (string.IsNullOrEmpty(value) || !_typeReplacerCache.TryGetValue(typeName, out var cache) ||
            cache.GetText(value, null) is not { } str)
        {
            return false;
        }

        typeValue = str;
        return !string.IsNullOrEmpty(typeValue);
    }


    private string? TryGetTypeValue(string typeName, string value)
    {
        return TryGetTypeValue(typeName, value, null);
    }


    private string TryGetTypeValue(GroupType? type, string value)
    {
        if (type is null)
        {
            return value;
        }

        return TryGetTypeValue(type.Name, value) ?? value;
    }


    public string GetColumnFinalText(string value)
    {
        return TryGetTypeValue(ColumnKeyType, value);
    }

    public bool TryGetGap(string gapName, 
#if NET8_0_OR_GREATER
            [MaybeNullWhen(false)]
#endif
        out Gap gap)
    {
        return Options.Gaps.TryGetValue(gapName, out gap);
    }

    /// <summary>
    ///     尝试根据Gap配置名和值节点查找Gap配置，期间会检查ExcelDataNode中的Type和Name属性是否和Gap配置中的相同。
    /// </summary>
    public bool TryGetGap(string gapName, ExcelDataNode node, 
#if NET8_0_OR_GREATER
            [MaybeNullWhen(false)]
#endif
        out Gap gap)
    {
        gap = null!;

        if (!TryGetGap(gapName, node.GetPath(), out var gapObj) ||
            gapObj.Type != node.Type ||
            (gapObj.Name != "*" && gapObj.Name != node.Name))
        {
            return false;
        }

        gap = gapObj;
        return true;
    }

    /// <summary>
    ///     尝试依据配置名和节点路径获取Gap配置，期间会检查Gap中的Identifier配置列表。
    /// </summary>
    public bool TryGetGap(string gapName, IEnumerable<ExcelDataNodePathElement> path,
#if NET8_0_OR_GREATER
            [MaybeNullWhen(false)]
#endif
        out Gap gap)
    {
        gap = null!;

        var excelDataNodePathElements = path as ExcelDataNodePathElement[] ?? path.ToArray();
        if (!Options.Gaps.TryGetValue(gapName, out var gapObj) ||
            (gapObj.Type != "*" &&
             !excelDataNodePathElements.Any(e =>
                 e.Type == gapObj.Type && (gapObj.TypeValue == "*" || e.Name == gapObj.TypeValue))))
        {
            return false;
        }

        if (_gapIdentifierCaches.TryGetValue(gapObj, out var cache) &&
            !cache.Test(excelDataNodePathElements))
        {
            return false;
        }

        gap = gapObj;
        return true;
    }


    /// <summary>
    ///     使用 Gap.LeftIndex 和 Gap.RightIndex 计算 Gap 差值，此方法不会检查 Gap.Indices 的配置。
    /// </summary>
    private GapCalculateResult CalculateGap(Gap gap, ExcelData data, int leftIndex, int rightIndex)
    {
        if (!data.TryGetValue(leftIndex, out var leftValue) ||
            !data.TryGetValue(rightIndex, out var rightValue) ||
            leftValue.Data == null ||
            rightValue.Data == null)
        {
            return GapCalculateResult.Failure;
        }
            
        return CalculateGap(gap, (decimal)leftValue.Data, (decimal)rightValue.Data, leftValue.NumberFormat);
    }


    /// <summary>
    ///     优先使用 GapIndex.LeftIndex 和 GapIndex.RightIndex 计算 Gap 差值。
    /// </summary>
    public GapCalculateResult CalculateGap(Gap gap, ExcelData data, GapIndex index)
    {
        return CalculateGap(gap, data,
            index.LeftIndex <= 0 ? gap.LeftIndex : index.LeftIndex,
            index.RightIndex <= 0 ? gap.RightIndex : index.RightIndex);
    }


    /// <summary>
    ///     使用传入的Gap配置进行减法计算。
    /// </summary>
    private GapCalculateResult CalculateGap(Gap gap, decimal? left, decimal? right, string numberFormat)
    {
        if (left == null || right == null)
        {
            return GapCalculateResult.Failure;
        }

        var val = left - right;
        var mark = string.Empty;

        var testVal = numberFormat.EndsWith("%") ? val * 100 : val;

        if (!string.IsNullOrEmpty(gap.Threshold) &&
            Options.Thresholds.TryGetValue(gap.Threshold, out var threshold) &&
            Options.Marks.TryGetValue(gap.Mark, out var markObj))
        {
            if (threshold.IsClosed
                    ? (decimal)threshold.Upper < testVal
                    : (decimal)threshold.Upper <= testVal)
            {
                mark = markObj.Greater;
            }
            else if (threshold.IsClosed
                         ? (decimal)threshold.Lower > testVal
                         : (decimal)threshold.Lower >= testVal)
            {
                mark = markObj.Less;
            }
            else
            {
                mark = markObj.Fit;
            }
        }

        return new GapCalculateResult
        {
            Success = true,
            Result = (decimal)val,
            Mark = mark,
            NumberFormatLocal = numberFormat
        };
    }

    /// <summary>
    ///     使用给定的Gap配置名称查找已有配置并进行减法计算。
    /// </summary>
    public GapCalculateResult CalculateGap(string gapName, decimal? left, decimal? right, string numberFormat)
    {
        return !Options.Gaps.TryGetValue(gapName, out var gapObj)
            ? GapCalculateResult.Failure
            : CalculateGap(gapObj, left, right, numberFormat);
    }


    private FilterCacheCollection GetFilterCache(Export export)
    {
        if (_filterCache.TryGetValue(export, out var caches))
        {
            return caches;
        }

        caches = new FilterCacheCollection(this);

        foreach (var item in export.Filters)
        {
            caches.Add(item);
        }

        _filterCache.Add(export, caches);
        return caches;
    }


    /// <summary>
    ///     判断给定的节点路径是否包含已配置的被筛选掉的类型和对应值。如果配置的筛选值是空值，将同时筛掉不包含给定类型的节点。
    /// </summary>
    /// <param name="export">指定的输出配置</param>
    /// <param name="path">待检查的节点路径。</param>
    public bool IsFilteredOut(Export export, IList<ExcelDataNodePathElement> path)
    {
        return export.Filters.Count != 0 && GetFilterCache(export).CheckNodePath(path);
    }


    /// <summary>
    ///     判断给定的类型名和类型值是否符合已配置的筛选器配置。
    /// </summary>
    public bool IsFilteredOut(Export export, string typeName, string typeValue)
    {
        return export.Filters.Count != 0 && GetFilterCache(export).CheckValue(typeName, typeValue);
    }


    public bool IsGroupFilteredOut(Export export, string groupSettingName, string groupValue)
    {
        // 如果给定名称是分组名，再检查给定值
        return _groupMap.ContainsKey(groupSettingName) &&
               GetFilterCache(export).CheckValue(groupSettingName, groupValue);
    }


    /// <summary>
    ///     从给定节点向上查找（包含给定节点）指定类型的节点，如果没有找到，返回null。
    /// </summary>
    private static ExcelDataNode? FindTypeNode(ExcelDataNode? node, string type)
    {
        var n = node;

        while (n != null)
        {
            if (n.Type == type)
            {
                return n;
            }

            n = n.Parent;
        }

        return null;
    }


    /// <summary>
    ///     已有节点列表使用指定的类型值定义顺序进行排序。
    /// </summary>
    public void OrderBy(Export export, List<ExcelDataNode> nodes)
    {
        if (string.IsNullOrEmpty(export.OrderBy) ||
            !Options.Types.Settings.TryGetValue(export.OrderBy, out var typeToOrderBy))
        {
            return;
        }

        if (!_orderCache.TryGetValue(export, out var orderList))
        {
            orderList = new List<string>();

            for (var i = 0; i < typeToOrderBy.Values.Count; i++)
            {
                var val = typeToOrderBy.Values[i];
                if (typeToOrderBy.Replacements != null && i < typeToOrderBy.Replacements.Count &&
                    !string.IsNullOrEmpty(typeToOrderBy.Replacements[i]))
                {
                    val = typeToOrderBy.Replacements[i];
                }

                orderList.Add(val);
            }

            _orderCache.Add(export, orderList);
        }

        nodes.Sort((a, b) =>
        {
            var left = FindTypeNode(a, export.OrderBy);
            var right = FindTypeNode(b, export.OrderBy);

            if (left == null)
            {
                return 1;
            }

            if (right == null)
            {
                return -1;
            }

            return orderList.IndexOf(left.Name) - orderList.IndexOf(right.Name);
        });
    }

    private class ReplacerCache(GroupType typeObj)
    {
        public GroupType TypeObj { get; } = typeObj;

        public RegexManager ValueRegex { get; } = new()
        {
            IgnoreCase = typeObj.IgnoreCase,
            Exactly = typeObj.Exactly
        };

        public List<Replacer?> Replacers { get; } = [];

        public HashSet<string> FinalValues { get; } = [];

        public bool HasAlias { get; set; }


        public bool TryGetReplacer(string source, 
#if NET8_0_OR_GREATER
                [MaybeNullWhen(false)]
#endif
            out Replacer replacer)
        {
            replacer = null!;
            var index = ValueRegex.SearchIndex(source);

            if (index <= -1 || 
                index >= Replacers.Count ||
                Replacers[index] is not { } rep)
            {
                return false;
            }

            replacer = rep;
            return true;
        }


        public string? GetText(string source, Func<string, string?>? getter)
        {
            var index = ValueRegex.SearchIndex(source);

            if (index <= -1 || index >= Replacers.Count)
            {
                return null;
            }

            var replacer = Replacers[index];
            return replacer != null ? replacer.Replace(getter) : source;
        }
    }


    private class GapIdentifierCache
    {
        // 有效值
        private readonly HashSet<string> _effectiveValues;

        // 无效值
        private readonly HashSet<string> _excludeValues;

        internal GapIdentifierCache(string type)
        {
            _effectiveValues = [];
            _excludeValues = [];
            Type = type;
        }

        /// <summary>
        ///     类型名
        /// </summary>
        private string Type { get; }

        /// <summary>
        ///     当前的表达式是否是排除值表达式。
        /// </summary>
        private bool IsAnyValueExpression { get; set; }

        /// <summary>
        ///     是否是排除所有值的表达式。
        /// </summary>
        private bool IsAnyValueExclude { get; set; }

        /// <summary>
        ///     判断给定的类型和类型名是否符合Gap类型筛选器。
        ///     如果不应该计算Gap，返回false。
        /// </summary>
        /// <param name="type">类型名</param>
        /// <param name="typeName">类型值</param>
        public bool Test(string type, string typeName)
        {
            return (Type == "*" || Type == type) /* 检查类型是否符合要求 */
                   && !IsAnyValueExclude /* 必须不能是排除任意值的表达式 */
                   && !_excludeValues.Contains(typeName) /* 必须不能在排除的值列表中 */
                   && (IsAnyValueExpression || _effectiveValues.Contains(typeName));
        }


        /// <summary>
        ///     向有效值集合中添加新的值。
        /// </summary>
        /// <param name="value"></param>
        public void Join(string value)
        {
            var expr = value;
            var isExclude = false;

            if (expr.StartsWith("^"))
            {
                expr = expr.Substring(1);
                isExclude = true;
            }

            if (expr == "*")
            {
                IsAnyValueExclude = isExclude;
                IsAnyValueExpression = true;
                _effectiveValues.Clear();
                _excludeValues.Clear();
            }
            else
            {
                if (isExclude)
                {
                    _excludeValues.Add(expr);
                }
                else
                {
                    _effectiveValues.Add(expr);
                }
            }
        }
    }


    private class GapIdentifierCacheCollection
    {
        private readonly Dictionary<string, GapIdentifierCache> _cache;

        private readonly Gap _gapObj;
        private SimpleTypeExpression? _expression;

        internal GapIdentifierCacheCollection(Gap gap)
        {
            _gapObj = gap;
            _cache = new Dictionary<string, GapIdentifierCache>();
        }

        /// <summary>
        ///     向Gap识别集合中添加新的类型绑定的表达式。
        /// </summary>
        /// <param name="type">类型名</param>
        /// <param name="expression">表达式</param>
        public void Add(string type, string expression)
        {
            if (!_cache.TryGetValue(type, out var item))
            {
                item = new GapIdentifierCache(type);
                _cache.Add(type, item);
            }

            item.Join(expression);
        }


        /// <summary>
        ///     向Gap识别集合中添加新的简单表达式。
        /// </summary>
        /// <param name="expression">表达式</param>
        public void AddSimpleExpression(string expression)
        {
            _expression = SimpleTypeExpressionParser.Parse(expression);
        }
            
        /// <summary>
        ///     检测给定类型名和类型值是否符合已有的Gap筛选器，
        ///     Gap的筛选器之间是或的关系。此处只判别已经配置了的筛选器，
        ///     如果指定类型的筛选器没有配置，将返回false。
        /// </summary>
        /// <param name="type">类型名</param>
        /// <param name="value">类型值</param>
        private bool Test(string type, string value)
        {
            // 如果配置了表达式，检查类型是否存在即可
            if (_expression?.IsEmpty == false)
            {
                return _expression.Exec(type, value);
            }

            return _cache.TryGetValue(type, out var identifier) && identifier.Test(type, value);
        }


        /// <summary>
        ///     测试给定节点路径是否满足当前的标识配置。
        /// </summary>
        /// <param name="path">节点路径</param>
        /// <returns></returns>
        public bool Test(IEnumerable<ExcelDataNodePathElement> path)
        {
            var pathDict = new Dictionary<string, string>();
            var elementTest = false;

            foreach (var element in path)
            {
                pathDict.SetValue(element.Type, element.Name);

                if (!elementTest && Test(element.Type, element.Name))
                {
                    elementTest = true;
                }
            }

            // 检查路径是否符合 Gap 配置的类型和名称。
            if (!(_gapObj.Type == "*" || (
                        pathDict.TryGetValue(_gapObj.Type, out var type) &&
                        (_gapObj.TypeValue == "*" || _gapObj.TypeValue == type)
                    )
                )
               )
            {
                return false;
            }

            // SimpleExpression 中的标识符名是且的关系，要求同时满足。
            return _expression?.Exec(pathDict) ?? elementTest;
        }
    }

    public struct GapCalculateResult
    {
        public bool Success;
        public decimal Result;
        public string Mark;
        public string NumberFormatLocal;

        public static readonly GapCalculateResult Failure = new()
        {
            Success = false,
            Result = 0,
            Mark = string.Empty,
            NumberFormatLocal = "general"
        };
    }


    private class FilterCache
    {
        private readonly HashSet<string> _values;

        internal FilterCache(string filterType, params string[] vals)
        {
            FilterType = filterType;
            _values = [..vals];
        }

        /// <summary>
        ///     检查的类型名。
        /// </summary>
        public string FilterType { get; }


        /// <summary>
        ///     向集合末尾添加新的值。
        /// </summary>
        public void AddValue(string value)
        {
            _values.Add(value);
        }

        /// <summary>
        ///     判断当前集合是否包含给定值。
        /// </summary>
        public bool Contains(string value)
        {
            return _values.Contains(value);
        }
    }


    private class FilterCacheCollection
    {
        private readonly List<FilterCache> _filters;

        private readonly OptionHelper _helper;
        private readonly HashSet<string> _typeToRemoveWhenNotExist;

        internal FilterCacheCollection(OptionHelper optionHelper)
        {
            _helper = optionHelper;
            _filters = [];
            _typeToRemoveWhenNotExist = [];
        }


        /// <summary>
        ///     向筛选器集合中添加新的内容。类型相同的对象不会重复添加，如果新添加的值包含空字符串，
        ///     此类型将被添加进不允许空白的类型集合中。
        /// </summary>
        public void Add(ExportFilter filter)
        {
            var exist = _filters.Find(e => e.FilterType == filter.Type);

            if (exist != null)
            {
                exist.AddValue(filter.Name);
            }
            else
            {
                _filters.Add(new FilterCache(filter.Type, filter.Name));
            }

            if (string.IsNullOrEmpty(filter.Name) && !_helper._groupMap.ContainsKey(filter.Type))
            {
                _typeToRemoveWhenNotExist.Add(filter.Type);
            }
        }

        /// <summary>
        ///     检查给定的节点路径是否应该被筛选掉。如果应当被筛选掉，返回true。
        /// </summary>
        public bool CheckNodePath(IEnumerable<ExcelDataNodePathElement> path)
        {
            var excelDataNodePathElements =
                path as ExcelDataNodePathElement[] ?? path.ToArray();
            if (_typeToRemoveWhenNotExist.Any(t => excelDataNodePathElements.All(e => e.Type != t)))
            {
                return true;
            }

            return (from item in excelDataNodePathElements
                let flt = _filters.FirstOrDefault(e => e.FilterType == item.Type)
                select flt != null && flt.Contains(item.Name)).FirstOrDefault();
        }

        /// <summary>
        ///     检查给定类型和类型值是否应该被筛选掉，如果应当被筛选掉，返回true。
        /// </summary>
        public bool CheckValue(string typeName, string typeValue)
        {
            var flt = _filters.FirstOrDefault(e => e.FilterType == typeName);
            return flt != null && flt.Contains(typeValue);
        }
    }
}